#include "sfx.h"

#ifdef USE_API_SFX_SDL

#ifdef UGLY_HACK_FOR_THOSE_WHO_DONT_KNOW_HOWTO_INSTALL_SDL
#include <SDL.h>
#include <SDL_audio.h>
#else
#include <SDL/SDL.h>
#include <SDL/SDL_audio.h>
#endif

#define MAX_CHANNELS 8

static int _sfx_sound_state;

typedef struct
{
    const char *path;
    SDL_AudioSpec sound;
} Sound;

typedef struct
{
    Sound *sound;
    int dpos;
    int dlen;
} Channel;

static Sound _sfx_sounds[64];
static Channel _sfx_channels[MAX_CHANNELS];
static SDL_AudioSpec _sfx_soundcard;
static int _sfx_soundcard_opened;

const char *sfx_sounds[] =
{
    "sounds/bruit_deplacement_menu.wav",
    "sounds/ENTRE_MENU.wav",
    "sounds/bruit_rebond_balle.wav",
    "sounds/neon.wav",
    "sounds/neonON3.wav",
    "sounds/neonON.wav",
    "sounds/neonON2.wav",
} ;

int  _sfx_load_sounds(void);
void _sfx_free_sounds(void);
void _sfx_mix(void *unused, Uint8 *stream, int len);

int  _sfx_load_sounds(void)
{
    for(int i = 0; i < SFX_SOUND_LAST; i++)
    {
        Sound *sound = &_sfx_sounds[i];
        if(SDL_LoadWAV(sfx_sounds[i], &sound->sound, (Uint8**)&sound->sound.userdata, &sound->sound.size) == 0)
        {
            return 1;
        }

        SDL_AudioCVT cvt;
        SDL_BuildAudioCVT(&cvt, sound->sound.format, sound->sound.channels, sound->sound.freq,
                            _sfx_soundcard.format,   _sfx_soundcard.channels,   _sfx_soundcard.freq);

        cvt.buf = (Uint8*)malloc(sound->sound.size);
        memcpy(cvt.buf, sound->sound.userdata, sound->sound.size);
        cvt.len = sound->sound.size / cvt.len_mult;
        SDL_ConvertAudio(&cvt);
        SDL_FreeWAV((Uint8*)sound->sound.userdata);
        sound->sound.userdata = cvt.buf;
    }
    return 0;
}

void _sfx_free_sounds(void)
{
    for(int i = 0; i < SFX_SOUND_LAST; i++)
    {
        Sound *sound = &_sfx_sounds[i];
        free(sound->sound.userdata);
    }
    memset(_sfx_sounds, 0, sizeof(Sound)*64);
    return;
}


void _sfx_mix(void *unused, Uint8 *stream, int len)
{
    int i;
    int amount;

    for ( i=0; i<MAX_CHANNELS; ++i )
    {
        Channel *channel = &_sfx_channels[i];
        if(channel->sound != 0)
        {
            amount = (channel->dlen - channel->dpos);
            if ( amount > len )
            {
                amount = len;
            }
            SDL_MixAudio(stream, &((Uint8*)(channel->sound->sound.userdata))[channel->dpos], amount, SDL_MIX_MAXVOLUME);
            channel->dpos += amount;

            /* Check if channel has finished playing */
            if(channel->dpos == channel->dlen)
            {
                channel->sound = 0;
                channel->dpos = 0;
                channel->dlen = 0;
            }
        }
    }
}

void sfx_init(void)
{
    if(SDL_InitSubSystem(SDL_INIT_AUDIO) != 0)
    {
        printf("ERR:Couldn't initialize SDL audio subsystem: %s\n", SDL_GetError());
        puts("ERR:Sound disabled");
        _sfx_soundcard_opened = 0;
        return;
    }
    /* Open sound card */
    _sfx_soundcard.freq = 44100;
    _sfx_soundcard.format = AUDIO_S16;
    _sfx_soundcard.channels = 2;
    _sfx_soundcard.samples = 1024;
    _sfx_soundcard.callback = _sfx_mix;
    _sfx_soundcard.userdata = 0;

    if(SDL_OpenAudio(&_sfx_soundcard, 0) != 0)
    {
        printf("ERR:Couldn't open soundcard: %s\n", SDL_GetError());
        puts("ERR:Sound disabled");
        _sfx_soundcard_opened = 0;
        return;
    }
    else
    {
        _sfx_soundcard_opened = 1;
    }

    /* Load sound files */
    if(_sfx_load_sounds() != 0)
    {
        puts("ERR:Couldn't load sound files");
        exit(EXIT_FAILURE);
    }
    SDL_PauseAudio(0);
}

void sfx_exit(void)
{
    _sfx_free_sounds();
    SDL_CloseAudio();
    SDL_QuitSubSystem(SDL_INIT_AUDIO);
    _sfx_soundcard_opened = 0;
    return;
}

void sfx_sound_play(SFX_SOUND sound)
{
    if(_sfx_sound_state == 1 && _sfx_soundcard_opened == 1)
    {
        Sound *sfx = &_sfx_sounds[sound];
        Channel *channel;

        /* Find free channel */
        for(int i = 0; i < MAX_CHANNELS; i++)
        {
            channel = &_sfx_channels[0];
            if(channel->sound == 0) break;
        }

        channel->dlen = sfx->sound.size;
        channel->dpos = 0;
        channel->sound = sfx;
    }
}

int sfx_set_sound_state(int stateValue)
{
    if(_sfx_soundcard_opened == 1)
    {
        _sfx_sound_state = stateValue;
        SDL_PauseAudio(!stateValue);
    }
    else
    {
        _sfx_sound_state = 0;
    }
    return 0;
}

void sfx_get_sound_state(int *stateValue)
{
    *stateValue = _sfx_sound_state;
}


#endif
